﻿using NModbus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CentralMonitoring.Protocol
{
    public class PLC
    {
        public static async Task<ushort[]> ModbusTcpReadRegisters(ushort startAddress, ushort length)
        {
            {
                // configure socket
                INIFile ini = new INIFile("config.ini");
                string ip = ini.IniReadValue("PLC", "DeviceIp");
                string port = ini.IniReadValue("PLC", "DevicePort");
                TcpClient client = new TcpClient();
                try
                {
                    client = new TcpClient(ip, int.Parse(port));
                }
                catch (Exception)
                {
                    return null;
                }

                var factory = new ModbusFactory();
                IModbusMaster master = factory.CreateMaster(client);

                ushort[] registers = null;
                var cts = new CancellationTokenSource();
                // 创建一个定时器
                Timer timer = new Timer(async (state) =>
                {
                    try
                    {
                        // 在这里进行读取操作
                        var res = await master.ReadHoldingRegistersAsync(0x01, startAddress, length);
                        registers = res;
                        if (res != null)
                            if (!cts.IsCancellationRequested)
                                cts.Cancel();
                            else
                                return;
                    }
                    catch (Exception)
                    {
                        // 处理异常，例如记录日志
                        //Console.WriteLine($"Error occurred: {ex.Message}");
                        registers = null;
                    }
                }, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); // 从现在开始，每 1 秒执行一次

                // 等待一段时间，以便定时器有机会执行
                try
                {
                    await Task.Delay(TimeSpan.FromSeconds(5), cts.Token);
                }
                catch (Exception)
                {
                    // 任务被取消时的处理，可根据需要添加逻辑
                    //timer.Dispose();
                }

                // 停止定时器
                timer.Dispose();

                return registers;
            }
        }

        public static async Task<PLCModel> GetData()
        {
            PLCModel model = null;
            bool state = false;
            await Task.Run(async () =>
            {
                // 测试连接状态
                var res = await ModbusTcpReadRegisters(47, 1);
                if (res == null) return;
                state = true;
            });
            if (!state) return model;

            model = new PLCModel();
            await Task.Run(async () =>
            {
                // 数据处理解析

                // Addr_43
                var res = await ModbusTcpReadRegisters(43, 1);
                model.VacuumPumpRunning = Convert.ToBoolean(res[0] & 0x0001);
                model.RootsPumpRunning = Convert.ToBoolean(res[0] & 0x0002);
                model.InletPumpRunning = Convert.ToBoolean(res[0] & 0x0004);
                model.OutletPumpRunning = Convert.ToBoolean(res[0] & 0x0008);

                model.MainSolenoidValveRunning = Convert.ToBoolean(res[0] & 0x0010);
                model.Heater1Running = Convert.ToBoolean(res[0] & 0x0020);
                model.Heater2Running = Convert.ToBoolean(res[0] & 0x0040);
                model.Heater3Running = Convert.ToBoolean(res[0] & 0x0080);

                model.Heater4Running = Convert.ToBoolean(res[0] & 0x0100);
                model.BypassSolenoidValveRunning = Convert.ToBoolean(res[0] & 0x0200);
                model.InletSolenoidValve = Convert.ToBoolean(res[0] & 0x0400);
                model.AutoRun = Convert.ToBoolean(res[0] & 0x0800);

                model.OilInjectionRunning = Convert.ToBoolean(res[0] & 0x1000);
                model.OilDischargeRunning = Convert.ToBoolean(res[0] & 0x2000);
                model.VacuumRunning = Convert.ToBoolean(res[0] & 0x4000);
                model.DeviceRunning = Convert.ToBoolean(res[0] & 0x8000);

                // Addr_41
                res = await ModbusTcpReadRegisters(41, 1);
                model.EmergencyStopPressed = Convert.ToBoolean(res[0] & 0x0001);
                model.PhaseSequenceAlarm = Convert.ToBoolean(res[0] & 0x0002);
                model.VacuumOrRootsPumpOverload = Convert.ToBoolean(res[0] & 0x0004);
                model.InletPumpOverload = Convert.ToBoolean(res[0] & 0x0008);

                model.InletInverterFault = Convert.ToBoolean(res[0] & 0x0010);
                model.OutletInverterFault = Convert.ToBoolean(res[0] & 0x0020);
                model.OutletPumpOverload = Convert.ToBoolean(res[0] & 0x0040);
                model.OutletPumpOverheat = Convert.ToBoolean(res[0] & 0x0080);

                model.OilPanFull = Convert.ToBoolean(res[0] & 0x0100);
                model.OilMistSeparatorOilStored = Convert.ToBoolean(res[0] & 0x0200);
                model.FirstGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x0400);
                model.SecondGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x0800);

                model.ThirdGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x1000);
                model.FourthGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x2000);
                model.BoxTemperatureHigh = Convert.ToBoolean(res[0] & 0x4000);
                model.FoamAlarm = Convert.ToBoolean(res[0] & 0x8000);

                // Addr_42
                res = await ModbusTcpReadRegisters(42, 1);
                model.InletPumpPressureHighLowAlarm = Convert.ToBoolean(res[0] & 0x0001);
                model.InletPumpOutletPressureHighAlarm = Convert.ToBoolean(res[0] & 0x0002);
                model.InletPumpFlowSwitchAlarm = Convert.ToBoolean(res[0] & 0x0004);
                model.HeaterOutletTemperatureHigh = Convert.ToBoolean(res[0] & 0x0008);

                model.OutletPumpPressureHighAlarm = Convert.ToBoolean(res[0] & 0x0010);
                model.OutletPumpFlowSwitchAlarm = Convert.ToBoolean(res[0] & 0x0020);
                model.HighLiquidLevelAlarm = Convert.ToBoolean(res[0] & 0x0040);
                model.LowLiquidLevelAlarm = Convert.ToBoolean(res[0] & 0x0080);

                model.InletPressureDifferenceBlocked = Convert.ToBoolean(res[0] & 0x0100);
                model.OutletPressureDifferenceBlocked = Convert.ToBoolean(res[0] & 0x0200);

                model.DeviceAlarm = Convert.ToBoolean(res[0] & 0x2000);

                // Addr_37
                res = await ModbusTcpReadRegisters(37, 1);
                model.CumulativeRunTimeMinutes = (short)res[0];

                // Addr_38
                res = await ModbusTcpReadRegisters(38, 1);
                model.CumulativeRunTimeHours = (short)res[0];

                // Addr_39
                res = await ModbusTcpReadRegisters(39, 1);
                model.CumulativeRunTimeDays = (short)res[0];

                // Addr_45
                res = await ModbusTcpReadRegisters(45, 1);
                model.DeviceStatus = (short)res[0];

                // Addr_47
                res = await ModbusTcpReadRegisters(47, 1);
                model.CurrentRunMinutes = (short)res[0];

                // Addr_48
                res = await ModbusTcpReadRegisters(48, 1);
                model.CurrentRunHours = (short)res[0];

                // Addr_49
                res = await ModbusTcpReadRegisters(49, 1);
                model.CurrentRunDays = (short)res[0];

                // Addr_180
                res = await ModbusTcpReadRegisters(180, 1);
                model.InletFilterLife = (short)res[0];

                // Addr_181
                res = await ModbusTcpReadRegisters(181, 1);
                model.OutletFilterLife = (short)res[0];

                // Addr_196
                res = await ModbusTcpReadRegisters(196, 1);
                model.OutletPumpRunRate = (short)res[0];

                // Addr_198
                res = await ModbusTcpReadRegisters(198, 1);
                model.InletPumpRunSpeed = (short)res[0];

                // Addr_200
                res = await ModbusTcpReadRegisters(200, 1);
                model.PressurePT01 = ((short)res[0]) / 100.0f;

                // Addr_201
                res = await ModbusTcpReadRegisters(201, 1);
                model.PressurePT02 = ((short)res[0]) / 100.0f;

                // Addr_202
                res = await ModbusTcpReadRegisters(202, 1);
                model.PressurePT03 = ((short)res[0]) / 100.0f;

                // Addr_203
                res = await ModbusTcpReadRegisters(203, 1);
                model.PressurePT04 = ((short)res[0]) / 100.0f;

                // Addr_204
                res = await ModbusTcpReadRegisters(204, 1);
                model.PressurePT05 = ((short)res[0]) / 100.0f;

                // Addr_210
                res = await ModbusTcpReadRegisters(210, 1);
                model.InletTemperatureTT01 = ((short)res[0]) / 10.0f;

                // Addr_211
                res = await ModbusTcpReadRegisters(211, 1);
                model.OutletTemperatureTT02 = ((short)res[0]) / 10.0f;

                // Addr_212
                res = await ModbusTcpReadRegisters(212, 1);
                model.HeaterOutletTemperatureTT03 = ((short)res[0]) / 10.0f;

                // Addr_213
                res = await ModbusTcpReadRegisters(213, 1);
                model.HeaterProtectionTemperatureTT04 = ((short)res[0]) / 10.0f;

                // Addr_326
                res = await ModbusTcpReadRegisters(326, 1);
                model.InletFlowMeterFT01 = (short)res[0];

                // Addr_327
                res = await ModbusTcpReadRegisters(327, 1);
                model.OutletFlowMeterFT02 = (short)res[0];

                // Addr_218
                res = await ModbusTcpReadRegisters(218, 1);
                model.InletFilter013PressureDifference = ((short)res[0]) / 100.0f;

                // Addr_219
                res = await ModbusTcpReadRegisters(219, 1);
                model.OutletFilter010PressureDifference = ((short)res[0]) / 100.0f;

                // Addr_230
                res = await ModbusTcpReadRegisters(230, 2);
                model.ContainerVacuumDPT01 = (int)(res[0] << 16 | res[1]);

                // Addr_232
                res = await ModbusTcpReadRegisters(232, 2);
                model.TransformerVacuumDPT02 = (int)(res[0] << 16 | res[1]);
            });

            return model;
        }
    }

    public class PLCModel
    {
        /// <summary>
        /// 设备运行状态
        /// </summary>
        public short DeviceStatus { get; set; }

        /// <summary>
        /// 累计运行时间（分钟）
        /// </summary>
        public short CumulativeRunTimeMinutes { get; set; }

        /// <summary>
        /// 累计运行时间（小时）
        /// </summary>
        public short CumulativeRunTimeHours { get; set; }

        /// <summary>
        /// 累计运行时间（天）
        /// </summary>
        public short CumulativeRunTimeDays { get; set; }

        /// <summary>
        /// 当前运行分
        /// </summary>
        public short CurrentRunMinutes { get; set; }

        /// <summary>
        /// 当前运行时
        /// </summary>
        public short CurrentRunHours { get; set; }

        /// <summary>
        /// 当前运行天
        /// </summary>
        public short CurrentRunDays { get; set; }

        /// <summary>
        /// 进口过滤器寿命
        /// </summary>
        public short InletFilterLife { get; set; }

        /// <summary>
        /// 出口过滤器寿命
        /// </summary>
        public short OutletFilterLife { get; set; }

        /// <summary>
        /// 出口泵运行速率
        /// </summary>
        public short OutletPumpRunRate { get; set; }

        /// <summary>
        /// 进口泵运行速度
        /// </summary>
        public short InletPumpRunSpeed { get; set; }

        /// <summary>
        /// 压力 PT01
        /// </summary>
        public float PressurePT01 { get; set; }

        /// <summary>
        /// 压力 PT02
        /// </summary>
        public float PressurePT02 { get; set; }

        /// <summary>
        /// 压力 PT03
        /// </summary>
        public float PressurePT03 { get; set; }

        /// <summary>
        /// 压力 PT04
        /// </summary>
        public float PressurePT04 { get; set; }

        /// <summary>
        /// 压力 PT05
        /// </summary>
        public float PressurePT05 { get; set; }

        /// <summary>
        /// 进口温度 TT01
        /// </summary>
        public float InletTemperatureTT01 { get; set; }

        /// <summary>
        /// 出口温度 TT02
        /// </summary>
        public float OutletTemperatureTT02 { get; set; }

        /// <summary>
        /// 加热器出口温度 TT03
        /// </summary>
        public float HeaterOutletTemperatureTT03 { get; set; }

        /// <summary>
        /// 加热器保护温度 TT04
        /// </summary>
        public float HeaterProtectionTemperatureTT04 { get; set; }

        /// <summary>
        /// 进口流量计 FT01
        /// </summary>
        public short InletFlowMeterFT01 { get; set; }

        /// <summary>
        /// 出口流量计 FT02
        /// </summary>
        public short OutletFlowMeterFT02 { get; set; }

        /// <summary>
        /// 进口过滤器 013 压差值
        /// </summary>
        public float InletFilter013PressureDifference { get; set; }

        /// <summary>
        /// 出口过滤器 010 压差值
        /// </summary>
        public float OutletFilter010PressureDifference { get; set; }

        /// <summary>
        /// 容器真空度值 DPT01
        /// </summary>
        public int ContainerVacuumDPT01 { get; set; }

        /// <summary>
        /// 变压器本体真空度 DPT02
        /// </summary>
        public int TransformerVacuumDPT02 { get; set; }

        /// <summary>
        /// 真空泵运行
        /// </summary>
        public bool VacuumPumpRunning { get; set; }

        /// <summary>
        /// 罗茨泵运行
        /// </summary>
        public bool RootsPumpRunning { get; set; }

        /// <summary>
        /// 进口泵运行
        /// </summary>
        public bool InletPumpRunning { get; set; }

        /// <summary>
        /// 出口泵运行
        /// </summary>
        public bool OutletPumpRunning { get; set; }

        /// <summary>
        /// 主电磁阀运行
        /// </summary>
        public bool MainSolenoidValveRunning { get; set; }

        /// <summary>
        /// 加热器 1 运行
        /// </summary>
        public bool Heater1Running { get; set; }

        /// <summary>
        /// 加热器 2 运行
        /// </summary>
        public bool Heater2Running { get; set; }

        /// <summary>
        /// 加热器 3 运行
        /// </summary>
        public bool Heater3Running { get; set; }

        /// <summary>
        /// 加热器 4 运行
        /// </summary>
        public bool Heater4Running { get; set; }

        /// <summary>
        /// 旁通电磁阀运行
        /// </summary>
        public bool BypassSolenoidValveRunning { get; set; }

        /// <summary>
        /// 进气电磁阀
        /// </summary>
        public bool InletSolenoidValve { get; set; }

        /// <summary>
        /// 自动运行
        /// </summary>
        public bool AutoRun { get; set; }

        /// <summary>
        /// 注油运行
        /// </summary>
        public bool OilInjectionRunning { get; set; }

        /// <summary>
        /// 排油运行
        /// </summary>
        public bool OilDischargeRunning { get; set; }

        /// <summary>
        /// 抽真空运行
        /// </summary>
        public bool VacuumRunning { get; set; }

        /// <summary>
        /// 设备运行
        /// </summary>
        public bool DeviceRunning { get; set; }

        /// <summary>
        /// 急停按钮按下
        /// </summary>
        public bool EmergencyStopPressed { get; set; }

        /// <summary>
        /// 相序报警
        /// </summary>
        public bool PhaseSequenceAlarm { get; set; }

        /// <summary>
        /// 真空泵或罗茨泵过载
        /// </summary>
        public bool VacuumOrRootsPumpOverload { get; set; }

        /// <summary>
        /// 进口泵过载或其冷却风扇过载
        /// </summary>
        public bool InletPumpOverload { get; set; }

        /// <summary>
        /// 进口变频器故障
        /// </summary>
        public bool InletInverterFault { get; set; }

        /// <summary>
        /// 出口变频器故障
        /// </summary>
        public bool OutletInverterFault { get; set; }

        /// <summary>
        /// 出口泵过载
        /// </summary>
        public bool OutletPumpOverload { get; set; }

        /// <summary>
        /// 出口泵过热
        /// </summary>
        public bool OutletPumpOverheat { get; set; }

        /// <summary>
        /// 集油盘满
        /// </summary>
        public bool OilPanFull { get; set; }

        /// <summary>
        /// 油雾分离器存油
        /// </summary>
        public bool OilMistSeparatorOilStored { get; set; }

        /// <summary>
        /// 第一组加热器过载
        /// </summary>
        public bool FirstGroupHeaterOverload { get; set; }

        /// <summary>
        /// 第二组加热器过载
        /// </summary>
        public bool SecondGroupHeaterOverload { get; set; }

        /// <summary>
        /// 第三组加热器过载
        /// </summary>
        public bool ThirdGroupHeaterOverload { get; set; }

        /// <summary>
        /// 第四组加热器过载
        /// </summary>
        public bool FourthGroupHeaterOverload { get; set; }

        /// <summary>
        /// 箱内温度高
        /// </summary>
        public bool BoxTemperatureHigh { get; set; }

        /// <summary>
        /// 泡沫多报警
        /// </summary>
        public bool FoamAlarm { get; set; }

        /// <summary>
        /// 进口泵进口压力高或低报警
        /// </summary>
        public bool InletPumpPressureHighLowAlarm { get; set; }

        /// <summary>
        /// 进口泵出口压力高报警
        /// </summary>
        public bool InletPumpOutletPressureHighAlarm { get; set; }

        /// <summary>
        /// 进口泵流量开关报警
        /// </summary>
        public bool InletPumpFlowSwitchAlarm { get; set; }

        /// <summary>
        /// 加热器出口温度高
        /// </summary>
        public bool HeaterOutletTemperatureHigh { get; set; }

        /// <summary>
        /// 出口泵压力高报警
        /// </summary>
        public bool OutletPumpPressureHighAlarm { get; set; }

        /// <summary>
        /// 出口泵流量开关报警
        /// </summary>
        public bool OutletPumpFlowSwitchAlarm { get; set; }

        /// <summary>
        /// 高液位报警
        /// </summary>
        public bool HighLiquidLevelAlarm { get; set; }

        /// <summary>
        /// 低液位报警
        /// </summary>
        public bool LowLiquidLevelAlarm { get; set; }

        /// <summary>
        /// 进口压差堵塞
        /// </summary>
        public bool InletPressureDifferenceBlocked { get; set; }

        /// <summary>
        /// 出口压差堵塞
        /// </summary>
        public bool OutletPressureDifferenceBlocked { get; set; }

        /// <summary>
        /// 设备报警
        /// </summary>
        public bool DeviceAlarm { get; set; }
    }
}
